import datetime

import requests
from bs4 import BeautifulSoup
from waste_collection_schedule import Collection
from waste_collection_schedule.exceptions import (
    SourceArgumentException,
    SourceArgumentNotFound,
)

# Title will show up in README.md and info.md
TITLE = "Nårab - Norra Åsbo Renhållnings AB"
DESCRIPTION = "Source script for narab.se"  # Describe your source

URL = "https://narab.se"

# Norra Åsbo Renhållnings AB (NÅRAB) provides waste collection services in the region of Skåne, Sweden.
# The main address for the company is narab.se, however the calendar is generated by a different service
# at www.narabtomningskalender.se which opens in a different window

# The calendar is generated in html format by the server with some javascript/jQuery to show tooltips and other live code.
# The user needs to input their address as the first step, and the Javascript will autocomplete the address and fetch
# other data like town, customer number, subscription number and type of customer (villa, residential, enterprise, etc.)
# which is later passed to the calendar creation API.
# The subscription number is shared between different type of customers in the same address (i.e, apartments and enterprise)
# so it shouldn't be used to index the calendars. KundNr (customer number) seems to be unique for each collection thus it's
# used for indexing.

# In order to obtain the customer number, the user needs to fetch his calendar and inspect the webpage (in Chrome or Firefox for example)
# Running the command narabKUNDNRData.value in the console returns the customer number.

# The script implements all the collection types supported by the tooltips contained in the page source, but not all of them have been tested.

TEST_CASES = {
    "Residential - Villa": {"address": "Helsingborgsvägen 31", "kundNr": 25494},
    "Residential - Apartment": {"address": "Hallandsvägen 9", "kundNr": 13726},
    "Commercial": {"address": "Hallandsvägen 9", "kundNr": 33159},
}

API_URL_FETCH_ADDRESS = (
    "https://www.narabtomningskalender.se/basfiler/system_ladda_adresser.php"
)
API_URL_FETCH_COLLECTIONS = (
    "https://www.narabtomningskalender.se/basfiler/online_kalender_skapa.php"
)

PARAM_DESCRIPTIONS = {
    "en": {
        "address": "Address for collection",
        "kundNr": "Customer number",
    },
    "de": {
        "address": "Adresse für die Sammlung",
        "kundNr": "Kundennummer",
    },
    "it": {
        "address": "Indirizzo per la raccolta",
        "kundNr": "Numero cliente",
    },
    "fr": {
        "address": "Adresse pour la collecte",
        "kundNr": "Numéro client",
    },
}

# Map collection names to icons
ICON_MAP = {
    "B1": "mdi:recycle-variant",
    "B1-F": "mdi:recycle-variant",
    "B1-H": "mdi:recycle-variant",
    "B2": "mdi:trash-can",
    "B2-F": "mdi:trash-can",
    "B2-H": "mdi:trash-can",
    "LB": "mdi:trash-can-outline",
    "LB-F": "mdi:trash-can-outline",
    "LB-H": "mdi:trash-can-outline",
    "KK": "mdi:delete-empty",
    "KK-F": "mdi:delete-empty",
    "KK-H": "mdi:delete-empty",
    "HAS": "mdi:delete",
    "HAS-F": "mdi:delete",
    "HAS-H": "mdi:delete",
    "HASD": "mdi:food-takeout-box-outline",
    "HASD-F": "mdi:food-takeout-box-outline",
    "HASD-H": "mdi:food-takeout-box-outline",
    "HAO": "mdi:delete-forever",
    "HAO-F": "mdi:delete-forever",
    "HAO-H": "mdi:delete-forever",
    "HAX": "mdi:delete-sweep",
    "HAX-F": "mdi:delete-sweep",
    "HAX-H": "mdi:delete-sweep",
    "FG": "mdi:bottle-wine",
    "FG-F": "mdi:bottle-wine",
    "FG-H": "mdi:bottle-wine",
    "OFG": "mdi:glass-pint-outline",
    "OFG-F": "mdi:glass-pint-outline",
    "OFG-H": "mdi:glass-pint-outline",
    "HPL": "mdi:bottle-soda-classic-outline",
    "HPL-F": "mdi:bottle-soda-classic-outline",
    "HPL-H": "mdi:bottle-soda-classic-outline",
    "PLF": "mdi:package-variant-closed",
    "PLF-F": "mdi:package-variant-closed",
    "PLF-H": "mdi:package-variant-closed",
    "MAT": "mdi:food-apple-outline",
    "MAT-F": "mdi:food-apple-outline",
    "MAT-H": "mdi:food-apple-outline",
    "MET": "mdi:can-outline",
    "MET-F": "mdi:can-outline",
    "MET-H": "mdi:can-outline",
    "MPL": "mdi:shopping-outline",
    "MPL-F": "mdi:shopping-outline",
    "MPL-H": "mdi:shopping-outline",
    "ORG": "mdi:leaf",
    "ORG-F": "mdi:leaf",
    "ORG-H": "mdi:leaf",
    "PAPP": "mdi:file-document-outline",
    "PAPP-F": "mdi:file-document-outline",
    "PAPP-H": "mdi:file-document-outline",
    "TIDN": "mdi:newspaper-variant-multiple-outline",
    "TIDN-F": "mdi:newspaper-variant-multiple-outline",
    "TIDN-H": "mdi:newspaper-variant-multiple-outline",
    "WELL": "mdi:archive-outline",
    "WELL-F": "mdi:archive-outline",
    "WELL-H": "mdi:archive-outline",
    "TRG": "mdi:leaf-maple",
    "TRG-F": "mdi:leaf-maple",
    "TRG-H": "mdi:leaf-maple",
    "LAT": "mdi:toilet",
    "LAT-H": "mdi:toilet",
    "BATT": "mdi:battery-outline",
    "BATT-H": "mdi:battery-outline",
    "FETT": "mdi:oil-lamp",
    "FETT-H": "mdi:oil-lamp",
    "OLJA": "mdi:oil",
    "OLJA-H": "mdi:oil",
    "SLAM": "mdi:water-opacity",
    "SLAM-H": "mdi:water-opacity",
    "FA": "mdi:help-circle-outline",
    "FA-H": "mdi:help-circle-outline",
}

# Map collection names to type of trash in Swedish, for reference purposes. Feel free to fix the translation as I am not fluent in Swedish.
collections_map = {
    "B1": "BEDA Kärl 1 - Förpackningar av Papper, Plast, Metall och Ofärgat glas",
    "B1-F": "BEDA Kärl 1 - Förpackningar av Papper, Plast, Metall och Ofärgat glas - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "B1-H": "BEDA Kärl 1 - Förpackningar av Papper, Plast, Metall och Ofärgat glas - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "B2": "BEDA Kärl 2 - Matavfall, Restavfall, Tidningar och Färgat glas",
    "B2-F": "BEDA Kärl 2 - Matavfall, Restavfall, Tidningar och Färgat glas - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "B2-H": "BEDA Kärl 2 - Matavfall, Restavfall, Tidningar och Färgat glas - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "LB": "LILLBEDA (endast Kärl 2) - Matavfall, Restavfall, Tidningar och Färgat glas",
    "LB-F": "LILLBEDA (endast Kärl 2) - Matavfall, Restavfall, Tidningar och Färgat glas - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "LB-H": "LILLBEDA (endast Kärl 2) - Matavfall, Restavfall, Tidningar och Färgat glas - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "KK": "Restavfallskärl",
    "KK-F": "Restavfallskärl - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "KK-H": "Restavfallskärl - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "HAS": "Restavfallskärl",
    "HAS-F": "Restavfallskärl - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "HAS-H": "Restavfallskärl - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "HASD": "Mat- & Restavfall delat kärl",
    "HASD-F": "Mat- & Restavfall delat kärl - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "HASD-H": "Mat- & Restavfall delat kärl - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "HAO": "Restavfallskärl",
    "HAO-F": "Restavfallskärl - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "HAO-H": "Restavfallskärl - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "HAX": "Restavfallskärl",
    "HAX-F": "Restavfallskärl - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "HAX-H": "Restavfallskärl - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "FG": "Färgat glas",
    "FG-F": "Färgat glas - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "FG-H": "Färgat glas - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "OFG": "Ofärgat glas",
    "OFG-F": "Ofärgat glas - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "OFG-H": "Ofärgat glas - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "HPL": "Hårdplast",
    "HPL-F": "Hårdplast - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "HPL-H": "Hårdplast - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "PLF": "Plastförpackningar",
    "PLF-F": "Plastförpackningar - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "PLF-H": "Plastförpackningar - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "MAT": "Matavfall",
    "MAT-F": "Matavfall - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "MAT-H": "Matavfall - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "MET": "Metallförpackningar",
    "MET-F": "Metallförpackningar - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "MET-H": "Metallförpackningar - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "MPL": "Mjukplast",
    "MPL-F": "Mjukplast - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "MPL-H": "Mjukplast - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "ORG": "Matavfall",
    "ORG-F": "Matavfall - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "ORG-H": "Matavfall - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "PAPP": "Pappersförpackningar",
    "PAPP-F": "Pappersförpackningar - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "PAPP-H": "Pappersförpackningar - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "TIDN": "Tidningar",
    "TIDN-F": "Tidningar - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "TIDN-H": "Tidningar - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "WELL": "Wellpapp",
    "WELL-F": "Wellpapp - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "WELL-H": "Wellpapp - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "TRG": "Trädgårdskärl",
    "TRG-F": "Trädgårdskärl - Flyttad tömningsdag! Den ordinare tömningsdagen är flyttad hit på grund av närliggande helgdag",
    "TRG-H": "Trädgårdskärl - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "LAT": "Latrin",
    "LAT-H": "Latrin - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "BATT": "Batterier",
    "BATT-H": "Batterier - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "FETT": "Fett",
    "FETT-H": "Fett - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "OLJA": "Olja",
    "OLJA-H": "Olja - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "SLAM": "Slam",
    "SLAM-H": "Slam - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
    "FA": "FA",
    "FA-H": "FA - Runt helgdagar kan det förekomma avvikelser från ordinarie tömningsdag. Dagen som visas är aktuell tömningsdag.",
}

# Map collection names to type of trash in English.
collections_map_en = {
    "B1": "BEDA Container 1 - Packaging of Paper, Plastic, Metal and Clear glass",
    "B1-F": "BEDA Container 1 - Packaging of Paper, Plastic, Metal and Clear glass - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "B1-H": "BEDA Container 1 - Packaging of Paper, Plastic, Metal and Clear glass - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "B2": "BEDA Container 2 - Food waste, Residual waste, Newspapers and Colored glass",
    "B2-F": "BEDA Container 2 - Food waste, Residual waste, Newspapers and Colored glass - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "B2-H": "BEDA Container 2 - Food waste, Residual waste, Newspapers and Colored glass - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "LB": "LILLBEDA (Container 2 only) - Food waste, Residual waste, Newspapers and Colored glass",
    "LB-F": "LILLBEDA (Container 2 only) - Food waste, Residual waste, Newspapers and Colored glass - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "LB-H": "LILLBEDA (Container 2 only) - Food waste, Residual waste, Newspapers and Colored glass - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "KK": "Residual waste container",
    "KK-F": "Residual waste container - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "KK-H": "Residual waste container - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "HAS": "Residual waste container",
    "HAS-F": "Residual waste container - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "HAS-H": "Residual waste container - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "HASD": "Food & Residual waste shared container",
    "HASD-F": "Food & Residual waste shared container - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "HASD-H": "Food & Residual waste shared container - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "HAO": "Residual waste container",
    "HAO-F": "Residual waste container - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "HAO-H": "Residual waste container - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "HAX": "Residual waste container",
    "HAX-F": "Residual waste container - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "HAX-H": "Residual waste container - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "FG": "Colored glass",
    "FG-F": "Colored glass - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "FG-H": "Colored glass - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "OFG": "Clear glass",
    "OFG-F": "Clear glass - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "OFG-H": "Clear glass - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "HPL": "Hard plastic",
    "HPL-F": "Hard plastic - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "HPL-H": "Hard plastic - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "PLF": "Plastic packaging",
    "PLF-F": "Plastic packaging - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "PLF-H": "Plastic packaging - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "MAT": "Food waste",
    "MAT-F": "Food waste - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "MAT-H": "Food waste - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "MET": "Metal packaging",
    "MET-F": "Metal packaging - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "MET-H": "Metal packaging - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "MPL": "Soft plastic",
    "MPL-F": "Soft plastic - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "MPL-H": "Soft plastic - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "ORG": "Food waste",
    "ORG-F": "Food waste - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "ORG-H": "Food waste - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "PAPP": "Paper packaging",
    "PAPP-F": "Paper packaging - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "PAPP-H": "Paper packaging - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "TIDN": "Newspapers",
    "TIDN-F": "Newspapers - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "TIDN-H": "Newspapers - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "WELL": "Corrugated cardboard",
    "WELL-F": "Corrugated cardboard - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "WELL-H": "Corrugated cardboard - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "TRG": "Garden container",
    "TRG-F": "Garden container - Moved emptying day! The regular emptying day has been moved here due to a nearby public holiday",
    "TRG-H": "Garden container - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "LAT": "Latrine",
    "LAT-H": "Latrine - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "BATT": "Batteries",
    "BATT-H": "Batteries - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "FETT": "Grease",
    "FETT-H": "Grease - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "OLJA": "Oil",
    "OLJA-H": "Oil - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "SLAM": "Sludge",
    "SLAM-H": "Sludge - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
    "FA": "FA",
    "FA-H": "FA - Around public holidays, there may be deviations from the regular emptying day. The day shown is the current emptying day.",
}


# Map Swedish month names to month numbers
swedish_months = {
    "Januari": 1,
    "Februari": 2,
    "Mars": 3,
    "April": 4,
    "Maj": 5,
    "Juni": 6,
    "Juli": 7,
    "Augusti": 8,
    "September": 9,
    "Oktober": 10,
    "November": 11,
    "December": 12,
}


class Source:
    def __init__(self, address: str, kundNr: int = 0):
        self._address = address
        self._kundNr = kundNr

    def parse_address_list(self, text: str):
        addresses = []
        for line in text.strip().splitlines():
            parts = line.split("|")
            if len(parts) != 5:
                raise ValueError(f"Expected 5 parts in line, got {len(parts)}: {line}")
            hsG, hsO, knR, abK, nrA = (p.strip() for p in parts)
            addresses.append(
                {"hsG": hsG, "hsO": hsO, "knR": knR, "abK": abK, "nrA": nrA}
            )
        return addresses

    def fetch(self) -> list[Collection]:
        # get address data
        r = requests.get(
            API_URL_FETCH_ADDRESS,
            params={
                "svar": self._address,
                "limit": "500",
                "timestamp": str(int(datetime.datetime.now().timestamp() * 1000)),
            },
        )
        r.raise_for_status()

        addresses = self.parse_address_list(r.text)
        if len(addresses) == 1:
            # If only one address is found, use it
            hsG, hsO, knR, abK, nrA = addresses[0].values()
        elif len(addresses) > 1:
            if self._kundNr == 0:
                # if multiple addresses are found but no kundNr is given, throw exception
                raise SourceArgumentException(
                    argument="address",
                    message=f"Multiple values found for the argument 'address' with the value '{self._address}'",
                )
            else:
                # If a kundNr is given, use the one with the matching kundNr
                for addr in addresses:
                    if addr["knR"] == str(self._kundNr):
                        hsG, hsO, knR, abK, nrA = addr.values()
                        break

                if not (hsG and hsO and knR and abK and nrA):
                    # If no matching kundNr is found, raise exception
                    raise SourceArgumentException(
                        argument="kundNr",
                        message=f"No results found for the argument 'kundNr' with the value '{self._kundNr}'. Please check the value and verify the address.",
                    )
        else:
            # If no addresses are found, raise exception
            raise SourceArgumentNotFound(
                argument="address",
                value=self._address,
            )

        # Request the calendar data
        # clid is a static value, might need to be updated if it's ever changed on the API side
        r = requests.get(
            API_URL_FETCH_COLLECTIONS,
            params={
                "hsG": hsG,
                "hsO": hsO,
                "knR": knR,
                "abK": abK,
                "nrA": nrA,
                "lang": "sv",
                "clid": "e97828682dc80c2b36df990778fb41a1",
            },
        )

        soup = BeautifulSoup(r.text, "html.parser")

        pickup_data = []

        for month_table in soup.select("#mainKalender table"):
            month_header = month_table.find("td", colspan="7")
            if not month_header:
                continue
            month_name = month_header.get_text(strip=True)

            for day_cell in month_table.find_all("td"):
                # Remove <span> elements so we don’t confuse their numbers with the day number
                cell_copy = day_cell.decode_contents()
                cell_no_spans = BeautifulSoup(cell_copy, "html.parser")
                for sp in cell_no_spans.find_all("span"):
                    sp.decompose()

                # Extract the day number from the remaining text
                day_text = (
                    cell_no_spans.get_text(strip=True).split()[0]
                    if cell_no_spans.get_text(strip=True)
                    else None
                )

                if not (day_text and day_text.isdigit()):
                    continue  # skip empty or invalid cells

                day_number = int(day_text)

                # Now loop over *all* spans in this cell (multiple trash types possible)
                for span in day_cell.find_all("span"):
                    classes = span.get("class", [])
                    trash_type = classes[0] if classes else None

                    if trash_type:
                        pickup_data.append(
                            {
                                "month": month_name,
                                "day": day_number,
                                "trash_type": trash_type,
                            }
                        )

        # Remove duplicates (if the same month, day, trash_type appears more than once)
        unique_data = []
        seen = set()
        for entry in pickup_data:
            key = (entry["month"], entry["day"], entry["trash_type"])
            if key not in seen:
                seen.add(key)
                unique_data.append(entry)

        # Create Collection objects from the unique data
        entries = []  # List that holds collection schedule

        for entry in unique_data:
            month = entry["month"]
            day = entry["day"]
            trash_type = entry["trash_type"]

            # Split the month string to get month name and year
            month_name, year_str = month.split(" - ")
            # print(month_name, year_str)
            month_number = swedish_months.get(month_name)
            if not month_number:
                continue
            year = int(year_str)
            # Create a datetime object for the collection date
            collection_date = datetime.date(year=year, month=month_number, day=day)

            # Create a Collection object
            entries.append(
                Collection(
                    date=collection_date,
                    t=collections_map_en[trash_type],
                    icon=ICON_MAP.get(trash_type),
                )
            )

        return entries
